home *** CD-ROM | disk | FTP | other *** search
/ Almathera Ten Pack 2: CDPD 1 / Almathera Ten on Ten - Disc 2: CDPD 1.iso / pd / 076-100 / 093 / microemacs / source / src.arc / input.c < prev    next >
C/C++ Source or Header  |  1987-08-16  |  10KB  |  495 lines

  1. /*    INPUT:    Various input routines for MicroEMACS 3.7
  2.         written by Daniel Lawrence
  3.         5/9/86                        */
  4.  
  5. #include    <stdio.h>
  6. #include    "estruct.h"
  7. #include    "edef.h"
  8.  
  9. /*
  10.  * Ask a yes or no question in the message line. Return either TRUE, FALSE, or
  11.  * ABORT. The ABORT status is returned if the user bumps out of the question
  12.  * with a ^G. Used any time a confirmation is required.
  13.  */
  14.  
  15. mlyesno(prompt)
  16.  
  17. char *prompt;
  18.  
  19. {
  20.     char c;            /* input character */
  21.     char buf[NPAT];        /* prompt to user */
  22.  
  23.     for (;;) {
  24.         /* build and prompt the user */
  25.         strcpy(buf, prompt);
  26.         strcat(buf, " [y/n]? ");
  27.         mlwrite(buf);
  28.  
  29.         /* get the responce */
  30.         c = tgetc();
  31.  
  32.         if (c == ectoc(abortc))        /* Bail out! */
  33.             return(ABORT);
  34.  
  35.         if (c=='y' || c=='Y')
  36.             return(TRUE);
  37.  
  38.         if (c=='n' || c=='N')
  39.             return(FALSE);
  40.     }
  41. }
  42.  
  43. /*
  44.  * Write a prompt into the message line, then read back a response. Keep
  45.  * track of the physical position of the cursor. If we are in a keyboard
  46.  * macro throw the prompt away, and return the remembered response. This
  47.  * lets macros run at full speed. The reply is always terminated by a carriage
  48.  * return. Handle erase, kill, and abort keys.
  49.  */
  50.  
  51. mlreply(prompt, buf, nbuf)
  52.     char *prompt;
  53.     char *buf;
  54. {
  55.     return(nextarg(prompt, buf, nbuf, ctoec('\n')));
  56. }
  57.  
  58. mlreplyt(prompt, buf, nbuf, eolchar)
  59.  
  60. char *prompt;
  61. char *buf;
  62. int eolchar;
  63.  
  64. {
  65.     return(nextarg(prompt, buf, nbuf, eolchar));
  66. }
  67.  
  68. /*    ectoc:    expanded character to character
  69.         colapse the CTRL and SPEC flags back into an ascii code   */
  70.  
  71. ectoc(c)
  72.  
  73. int c;
  74.  
  75. {
  76.     if (c & CTRL)
  77.         c = c & ~(CTRL | 0x40);
  78.     if (c & SPEC)
  79.         c= c & 255;
  80.     return(c);
  81. }
  82.  
  83. /*    ctoec:    character to extended character
  84.         pull out the CTRL and SPEC prefixes (if possible)    */
  85.  
  86. ctoec(c)
  87.  
  88. int c;
  89.  
  90. {
  91.         if (c>=0x00 && c<=0x1F)
  92.                 c = CTRL | (c+'@');
  93.         return (c);
  94. }
  95.  
  96. /* get a command name from the command line. Command completion means
  97.    that pressing a <SPACE> will attempt to complete an unfinished command
  98.    name if it is unique.
  99. */
  100.  
  101. int (*getname())()
  102.  
  103. {
  104. #if    ST520 & LATTICE
  105. #define register        
  106. #endif
  107.     register int cpos;    /* current column on screen output */
  108.     register int c;
  109.     register char *sp;    /* pointer to string for output */
  110.     register NBIND *ffp;    /* first ptr to entry in name binding table */
  111.     register NBIND *cffp;    /* current ptr to entry in name binding table */
  112.     register NBIND *lffp;    /* last ptr to entry in name binding table */
  113.     char buf[NSTRING];    /* buffer to hold tentative command name */
  114.     int (*fncmatch())();
  115.  
  116.     /* starting at the beginning of the string buffer */
  117.     cpos = 0;
  118.  
  119.     /* if we are executing a command line get the next arg and match it */
  120.     if (clexec) {
  121.         if (macarg(buf) != TRUE)
  122.             return(FALSE);
  123.         return(fncmatch(&buf[0]));
  124.     }
  125.  
  126.     /* build a name string from the keyboard */
  127.     while (TRUE) {
  128.         c = tgetc();
  129.  
  130.         /* if we are at the end, just match it */
  131.         if (c == 0x0d) {
  132.             buf[cpos] = 0;
  133.  
  134.             /* and match it off */
  135.             return(fncmatch(&buf[0]));
  136.  
  137.         } else if (c == ectoc(abortc)) {    /* Bell, abort */
  138.             ctrlg(FALSE, 0);
  139.             TTflush();
  140.             return( (int (*)()) NULL);
  141.  
  142.         } else if (c == 0x7F || c == 0x08) {    /* rubout/erase */
  143.             if (cpos != 0) {
  144.                 TTputc('\b');
  145.                 TTputc(' ');
  146.                 TTputc('\b');
  147.                 --ttcol;
  148.                 --cpos;
  149.                 TTflush();
  150.             }
  151.  
  152.         } else if (c == 0x15) {    /* C-U, kill */
  153.             while (cpos != 0) {
  154.                 TTputc('\b');
  155.                 TTputc(' ');
  156.                 TTputc('\b');
  157.                 --cpos;
  158.                 --ttcol;
  159.             }
  160.  
  161.             TTflush();
  162.  
  163.         } else if (c == ' ') {
  164. /* <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< */
  165.     /* attempt a completion */
  166.     buf[cpos] = 0;        /* terminate it for us */
  167.     ffp = &names[0];    /* scan for matches */
  168.     while (ffp->n_func != NULL) {
  169.         if (strncmp(buf, ffp->n_name, strlen(buf)) == 0) {
  170.             /* a possible match! More than one? */
  171.             if ((ffp + 1)->n_func == NULL ||
  172.                (strncmp(buf, (ffp+1)->n_name, strlen(buf)) != 0)) {
  173.                 /* no...we match, print it */
  174.                 sp = ffp->n_name + cpos;
  175.                 while (*sp)
  176.                     TTputc(*sp++);
  177.                 TTflush();
  178.                 return(ffp->n_func);
  179.             } else {
  180. /* << << << << << << << << << << << << << << << << << */
  181.     /* try for a partial match against the list */
  182.  
  183.     /* first scan down until we no longer match the current input */
  184.     lffp = (ffp + 1);
  185.     while ((lffp+1)->n_func != NULL) {
  186.         if (strncmp(buf, (lffp+1)->n_name, strlen(buf)) != 0)
  187.             break;
  188.         ++lffp;
  189.     }
  190.  
  191.     /* and now, attempt to partial complete the string, char at a time */
  192.     while (TRUE) {
  193.         /* add the next char in */
  194.         buf[cpos] = ffp->n_name[cpos];
  195.  
  196.         /* scan through the candidates */
  197.         cffp = ffp + 1;
  198.         while (cffp <= lffp) {
  199.             if (cffp->n_name[cpos] != buf[cpos])
  200.                 goto onward;
  201.             ++cffp;
  202.         }
  203.  
  204.         /* add the character */
  205.         TTputc(buf[cpos++]);
  206.     }
  207. /* << << << << << << << << << << << << << << << << << */
  208.             }
  209.         }
  210.         ++ffp;
  211.     }
  212.  
  213.     /* no match.....beep and onward */
  214.     TTbeep();
  215. onward:;
  216.     TTflush();
  217. /* <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< */
  218.         } else {
  219.             if (cpos < NSTRING-1 && c > ' ') {
  220.                 buf[cpos++] = c;
  221.                 TTputc(c);
  222.             }
  223.  
  224.             ++ttcol;
  225.             TTflush();
  226.         }
  227.     }
  228. }
  229.  
  230. /*    tgetc:    Get a key from the terminal driver, resolve any keyboard
  231.         macro action                    */
  232.  
  233. int tgetc()
  234.  
  235. {
  236.     int c;    /* fetched character */
  237.  
  238.     /* if we are playing a keyboard macro back, */
  239.     if (kbdmode == PLAY) {
  240.  
  241.         /* if there is some left... */
  242.         if (kbdptr < kbdend)
  243.             return((int)*kbdptr++);
  244.  
  245.         /* at the end of last repitition? */
  246.         if (--kbdrep < 1) {
  247.             kbdmode = STOP;
  248. #if    VISMAC == 0
  249.             /* force a screen update after all is done */
  250.             update(FALSE);
  251. #endif
  252.         } else {
  253.  
  254.             /* reset the macro to the begining for the next rep */
  255.             kbdptr = &kbdm[0];
  256.             return((int)*kbdptr++);
  257.         }
  258.     }
  259.  
  260.     /* fetch a character from the terminal driver */
  261.     c = TTgetc();
  262.  
  263.     /* record it for $lastkey */
  264.     lastkey = c;
  265.  
  266.     /* save it if we need to */
  267.     if (kbdmode == RECORD) {
  268.         *kbdptr++ = c;
  269.         kbdend = kbdptr;
  270.  
  271.         /* don't overrun the buffer */
  272.         if (kbdptr == &kbdm[NKBDM - 1]) {
  273.             kbdmode = STOP;
  274.             TTbeep();
  275.         }
  276.     }
  277.  
  278.     /* and finally give the char back */
  279.     return(c);
  280. }
  281.  
  282. /*    GET1KEY:    Get one keystroke. The only prefixs legal here
  283.             are the SPEC and CTRL prefixes.
  284.                                 */
  285.  
  286. get1key()
  287.  
  288. {
  289.     int    c;
  290. #if    AMIGA
  291.     int    d;
  292. #endif
  293.  
  294.     /* get a keystroke */
  295.         c = tgetc();
  296.  
  297. #if    MSDOS | ST520
  298.     if (c == 0) {                /* Apply SPEC prefix    */
  299.             c = tgetc();
  300.             if (c>=0x00 && c<=0x1F)        /* control key? */
  301.                     c = CTRL | (c+'@');
  302.         return(SPEC | c);
  303.     }
  304. #endif
  305.  
  306. #if    AMIGA
  307.     /* apply SPEC prefix */
  308.     if ((unsigned)c == 155) {
  309.         c = tgetc();
  310.  
  311.         /* first try to see if it is a cursor key */
  312.         if ((c >= 'A' && c <= 'D') || c == 'S' || c == 'T')
  313.             return(SPEC | c);
  314.  
  315.         /* next, a 2 char sequence */
  316.         d = tgetc();
  317.         if (d == '~')
  318.             return(SPEC | c);
  319.  
  320.         /* decode a 3 char sequence */
  321.         c = d + 32;
  322.         /* if a shifted function key, eat the tilde */
  323.         if (d >= '0' && d <= '9')
  324.             d = tgetc();
  325.         return(SPEC | c);
  326.     }
  327. #endif
  328.  
  329. #if  WANGPC
  330.     if (c == 0x1F) {            /* Apply SPEC prefix    */
  331.             c = tgetc();
  332.         return(SPEC | c);
  333.     }
  334. #endif
  335.  
  336.         if (c>=0x00 && c<=0x1F)                 /* C0 control -> C-     */
  337.                 c = CTRL | (c+'@');
  338.         return (c);
  339. }
  340.  
  341. /*    GETCMD:    Get a command from the keyboard. Process all applicable
  342.         prefix keys
  343.                             */
  344. getcmd()
  345.  
  346. {
  347.     int c;        /* fetched keystroke */
  348.  
  349.     /* get initial character */
  350.     c = get1key();
  351.  
  352.     /* process META prefix */
  353.     if (c == metac) {
  354.         c = get1key();
  355.             if (islower(c))        /* Force to upper */
  356.                     c ^= DIFCASE;
  357.             if (c>=0x00 && c<=0x1F)        /* control key */
  358.                 c = CTRL | (c+'@');
  359.         return(META | c);
  360.     }
  361.  
  362.     /* process CTLX prefix */
  363.     if (c == ctlxc) {
  364.         c = get1key();
  365.             if (c>='a' && c<='z')        /* Force to upper */
  366.                     c -= 0x20;
  367.             if (c>=0x00 && c<=0x1F)        /* control key */
  368.                 c = CTRL | (c+'@');
  369.         return(CTLX | c);
  370.     }
  371.  
  372.     /* otherwise, just return it */
  373.     return(c);
  374. }
  375.  
  376. /*    A more generalized prompt/reply function allowing the caller
  377.     to specify the proper terminator. If the terminator is not
  378.     a return ('\n') it will echo as "<NL>"
  379.                             */
  380. getstring(prompt, buf, nbuf, eolchar)
  381.  
  382. char *prompt;
  383. char *buf;
  384. int eolchar;
  385.  
  386. {
  387.     register int cpos;    /* current character position in string */
  388.     register int c;
  389.     register int quotef;    /* are we quoting the next char? */
  390.  
  391.     cpos = 0;
  392.     quotef = FALSE;
  393.  
  394.     /* prompt the user for the input string */
  395.     mlwrite(prompt);
  396.  
  397.     for (;;) {
  398.         /* get a character from the user */
  399.         c = get1key();
  400.  
  401.         /* If it is a <ret>, change it to a <NL> */
  402.         if (c == (CTRL | 0x4d))
  403.             c = CTRL | 0x40 | '\n';
  404.  
  405.         /* if they hit the line terminate, wrap it up */
  406.         if (c == eolchar && quotef == FALSE) {
  407.             buf[cpos++] = 0;
  408.  
  409.             /* clear the message line */
  410.             mlwrite("");
  411.             TTflush();
  412.  
  413.             /* if we default the buffer, return FALSE */
  414.             if (buf[0] == 0)
  415.                 return(FALSE);
  416.  
  417.             return(TRUE);
  418.         }
  419.  
  420.         /* change from command form back to character form */
  421.         c = ectoc(c);
  422.  
  423.         if (c == ectoc(abortc) && quotef == FALSE) {
  424.             /* Abort the input? */
  425.             ctrlg(FALSE, 0);
  426.             TTflush();
  427.             return(ABORT);
  428.         } else if ((c==0x7F || c==0x08) && quotef==FALSE) {
  429.             /* rubout/erase */
  430.             if (cpos != 0) {
  431.                 outstring("\b \b");
  432.                 --ttcol;
  433.  
  434.                 if (buf[--cpos] < 0x20) {
  435.                     outstring("\b \b");
  436.                     --ttcol;
  437.                 }
  438.  
  439.                 if (buf[cpos] == '\n') {
  440.                     outstring("\b\b  \b\b");
  441.                     ttcol -= 2;
  442.                 }
  443.                 TTflush();
  444.             }
  445.  
  446.         } else if (c == 0x15 && quotef == FALSE) {
  447.             /* C-U, kill */
  448.             while (cpos != 0) {
  449.                 outstring("\b \b");
  450.                 --ttcol;
  451.  
  452.                 if (buf[--cpos] < 0x20) {
  453.                     outstring("\b \b");
  454.                     --ttcol;
  455.                 }
  456.             }
  457.             TTflush();
  458.  
  459.         } else if (c == quotec && quotef == FALSE) {
  460.             quotef = TRUE;
  461.         } else {
  462.             quotef = FALSE;
  463.             if (cpos < nbuf-1) {
  464.                 buf[cpos++] = c;
  465.  
  466.                 if ((c < ' ') && (c != '\n')) {
  467.                     outstring("^");
  468.                     ++ttcol;
  469.                     c ^= 0x40;
  470.                 }
  471.  
  472.                 if (c != '\n') {
  473.                     if (disinp)
  474.                         TTputc(c);
  475.                 } else {    /* put out <NL> for <ret> */
  476.                     outstring("<NL>");
  477.                     ttcol += 3;
  478.                 }
  479.                 ++ttcol;
  480.                 TTflush();
  481.             }
  482.         }
  483.     }
  484. }
  485.  
  486. outstring(s)    /* output a string of characters */
  487.  
  488. char *s;    /* string to output */
  489.  
  490. {
  491.     if (disinp)
  492.         while (*s)
  493.             TTputc(*s++);
  494. }
  495.